package scala.Expression.For

object ForAlternative {

   //case 1
   // for(x <- expr1) yield expr2
   def foo1(l: List[Int]): List[Int] = {
      for (x <- l) yield (x + 1)
   }
   // expr1.map(x => expr2)
   def foo11(l: List[Int]): List[Int] = {
      l.map(x => x + 1)
   }

   // for(x <- expr1 if expr2) yield expr3
   def foo2(l: List[Int]): List[Int] = {
      for (x <- l if (x % 2 == 0)) yield (x * 2)
   }

   // expr1 filter(x => expr2) map (x => expr3)
   def foo22(l: List[Int]): List[Int] = {
      l.filter(x => x % 2 == 0).map(y => y * 2)
   }

   //case 2
   // for(x <- expr1) body
   def foo3(l: List[Int]): Int = {
      var sum = 0
      for (x <- l) {
         sum += x
      }
      sum
   }
   // expr1 foreach(x => body)
   def foo33(l: List[Int]): Int = {
      var sum = 0
      l foreach (x => sum += x)
      sum
   }
   // for(x <- expr1; if expr2; y <- expr3) body
   def foo4(xss: List[List[Int]]): Int = {
      var sum = 0
      for (xs <- xss; x <- xs)
         sum += x
      sum
   }
   // expr1 filter(x => expr2) foreach(x => expr3 foreach(y => body))
   def foo44(xss: List[List[Int]]): Int = {
      var sum = 0
      xss foreach (xs =>
         xs foreach (x => sum += x))
      sum
   }
   //another example
   def foo444(xss: List[List[Int]]): Int = {
      var sum = 0
      for (xs <- xss if (xs.length % 2 == 0); x <- xs)
         sum += x
      sum
   }
   def foo4444(xss: List[List[Int]]): Int = {
      var sum = 0
      xss.filter(xs => xs.length % 2 == 0).foreach(xs => xs.foreach(x => sum += x))
      sum
   }

   //test case
   val list: List[Int] = List(1, 2, 3, 4, 5)
   val llist = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9), List(1, 10), List(2, 10))
   val xss = List(List(1, 1), List(2, 2, 2), List(3, 3, 3, 3))
   val l: List[String] = List("mot", "hai", "ba", "bon")

   def main(args: Array[String]): Unit = {
      val r1 = foo1(list)
      val r11 = foo11(list)
      println(r1 + "\n" + r11)

      val r2 = foo2(list)
      val r22 = foo22(list)
      println(r2 + "\n" + r22)

      val t = foo444(llist)
      println(t)
      val t1 = foo4444(llist)
      println(t1)

      val m1 = list.map(x => x * 2)
      println(m1)
      val m2 = xss.flatMap(x => Demo.g(x))
      println(m2)
   }

}

object Demo {
   def map[A, B](xs: List[A], f: A => B): List[B] = {
      for (x <- xs) yield f(x)
   }

   def flatMap[A, B](xs: List[A], f: A => List[B]): List[B] = {
      for (x <- xs; y <- f(x)) yield y
   }

   def filter[A](xs: List[A], p: A => Boolean): List[A] = {
      for (x <- xs if p(x)) yield x
   }

   def g(xs: List[Int]): List[Int] = xs.map(mem => mem + 1)
}

/*




*/ 